package com.spsy.order.controller;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class OrderDataInserter {

    // 数据库配置
    private static final String DB_URL = "jdbc:mysql://localhost:3306/ry_2302a_order?useUnicode=true&characterEncoding=utf8&useSSL=false&rewriteBatchedStatements=true";
    private static final String DB_USER = "root";
    private static final String DB_PASSWORD = "root";

    // 插入配置
    private static final int TOTAL_RECORDS = 5000000;  // 总记录数
    private static final int THREAD_COUNT = 8;         // 线程数
    private static final int BATCH_SIZE = 1000;        // 每批次插入数量

    public static void main(String[] args) throws Exception {
        long startTime = System.currentTimeMillis();
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
        List<Future<Integer>> futures = new ArrayList<>();

        // 分配任务
        int baseCount = TOTAL_RECORDS / THREAD_COUNT;
        int remainder = TOTAL_RECORDS % THREAD_COUNT;

        for (int i = 0; i < THREAD_COUNT; i++) {
            int taskCount = baseCount + (i == THREAD_COUNT - 1 ? remainder : 0);
            futures.add(executor.submit(new InsertTask(i + 1, taskCount)));
        }

        // 等待完成并统计
        int totalInserted = 0;
        for (Future<Integer> future : futures) {
            totalInserted += future.get();
        }
        executor.shutdown();

        // 输出结果
        long costTime = System.currentTimeMillis() - startTime;
        System.out.printf("总插入: %d条, 耗时: %.2f秒, 平均速度: %.2f条/秒%n",
                totalInserted, costTime / 1000.0, totalInserted / (costTime / 1000.0));
    }

    static class InsertTask implements Callable<Integer> {
        private final int threadId;
        private final int totalCount;
        private static final String[] CITIES = {"北京市", "上海市", "广州市", "深圳市", "杭州市"};
        private static final String[] DISTRICTS = {"朝阳区", "海淀区", "静安区", "浦东区", "西湖区"};
        // 每个线程独立的随机数生成器，减少竞争
        private final Random random = new Random();

        public InsertTask(int threadId, int totalCount) {
            this.threadId = threadId;
            this.totalCount = totalCount;
        }

        @Override
        public Integer call() throws Exception {
            Connection conn = null;
            PreparedStatement pstmt = null;
            int inserted = 0;
            long threadStart = System.currentTimeMillis();

            try {
                // 建立连接
                conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
                conn.setAutoCommit(false);

                // 准备SQL
                String sql = "INSERT INTO `order` (" +
                        "order_no, order_no2, user_id, total_amount, discount_amount, " +
                        "shipping_fee, pay_amount, payment_method, payment_time, order_status, " +
                        "consignee, phone, address, remark" +
                        ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
                pstmt = conn.prepareStatement(sql);

                // 批量插入
                while (inserted < totalCount) {
                    int currentBatch = Math.min(BATCH_SIZE, totalCount - inserted);
                    pstmt.clearBatch();

                    for (int i = 0; i < currentBatch; i++) {
                        // 生成唯一订单号（确保不重复且长度合适）
                        String orderNo = generateUniqueOrderNo();
                        pstmt.setString(1, orderNo);

                        // 订单号2（使用不同前缀，确保长度一致）
                        String orderNo2 = random.nextDouble() < 0.3 ? "W" + orderNo.substring(1) : null;
                        pstmt.setString(2, orderNo2);

                        // 用户ID
                        pstmt.setLong(3, random.nextInt(10000) + 1);

                        // 金额计算
                        double totalAmt = 10 + random.nextDouble() * 9990;
                        double discount = totalAmt * random.nextDouble() * 0.3;
                        double shipFee = random.nextDouble() * 50;
                        double payAmt = totalAmt - discount + shipFee;

                        pstmt.setBigDecimal(4, BigDecimal.valueOf(totalAmt).setScale(2, RoundingMode.HALF_UP));
                        pstmt.setBigDecimal(5, BigDecimal.valueOf(discount).setScale(2, RoundingMode.HALF_UP));
                        pstmt.setBigDecimal(6, BigDecimal.valueOf(shipFee).setScale(2, RoundingMode.HALF_UP));
                        pstmt.setBigDecimal(7, BigDecimal.valueOf(payAmt).setScale(2, RoundingMode.HALF_UP));

                        // 支付方式
                        pstmt.setInt(8, random.nextInt(3) + 1);

                        // 支付时间
                        if (random.nextDouble() < 0.7) {
                            long daysAgo = random.nextInt(31);
                            pstmt.setTimestamp(9, new Timestamp(
                                    System.currentTimeMillis() - daysAgo * 86400000));
                        } else {
                            pstmt.setNull(9, Types.TIMESTAMP);
                        }

                        // 订单状态
                        pstmt.setInt(10, random.nextInt(5) + 1);

                        // 收货信息
                        if (random.nextDouble() < 0.8) {
                            pstmt.setString(11, "用户" + (random.nextInt(9000) + 1000));
                            pstmt.setString(12, "13" + (random.nextInt(90000000) + 10000000));
                            pstmt.setString(13, CITIES[random.nextInt(CITIES.length)] +
                                    DISTRICTS[random.nextInt(DISTRICTS.length)] +
                                    "小区" + (random.nextInt(200) + 1));
                        } else {
                            pstmt.setNull(11, Types.VARCHAR);
                            pstmt.setNull(12, Types.VARCHAR);
                            pstmt.setNull(13, Types.VARCHAR);
                        }

                        // 备注
                        pstmt.setString(14, random.nextDouble() < 0.2 ? "备注" + random.nextInt(10000) : null);

                        pstmt.addBatch();
                    }

                    pstmt.executeBatch();
                    conn.commit();
                    inserted += currentBatch;

                    // 打印进度
                    if (inserted % 100000 == 0) {
                        double speed = inserted / ((System.currentTimeMillis() - threadStart) / 1000.0);
                        System.out.printf("线程%d: 已插入%d条, 速度:%.2f条/秒%n",
                                threadId, inserted, speed);
                    }
                }
            } catch (SQLException e) {
                if (conn != null) conn.rollback();
                System.err.println("线程" + threadId + "错误: " + e.getMessage());
            } finally {
                if (pstmt != null) pstmt.close();
                if (conn != null) conn.close();
            }

            return inserted;
        }

        // 生成唯一订单号 - 采用多重唯一因子组合
        private String generateUniqueOrderNo() {
            // 1. 时间戳（毫秒+微秒）确保时间维度唯一
            long now = System.currentTimeMillis();
            String timePart = String.format("%013d", now); // 13位毫秒时间戳

            // 2. 线程ID确保多线程场景下唯一
            String threadPart = String.format("%02d", threadId); // 2位线程ID

            // 3. 随机数确保同一线程同一时间戳下唯一
            String randomPart = String.format("%05d", random.nextInt(100000)); // 5位随机数

            // 4. UUID片段作为最终保障
            String uuidPart = UUID.randomUUID().toString().substring(0, 5); // 5位UUID片段

            // 组合订单号（总长度：1+13+2+5+5=26，远小于32）
            return "O" + timePart + threadPart + randomPart + uuidPart;
        }
    }
}
